-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
fix: Server internal error details leaking in error messages returned to clients #9937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
I will reformat the title to use the proper commit message syntax. |
|
🚀 Thanks for opening this pull request! |
📝 WalkthroughWalkthroughAdds centralized sanitized-error helpers that log detailed server-side messages and return a generic "Permission denied" to clients. Replaces many direct Parse.Error/HTTP error throws across routers, controllers, REST/GraphQL layers, and middleware with sanitized-error constructors; tests updated to expect the generic message and assert sanitized logging. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Server
participant Logger
note over Client,Server: Authorization failure path (sanitized)
Client->>Server: Request lacking permission / invalid key
Server->>Logger: log("Sanitized error: " + detailedMessage)
alt Respond to client
Server-->>Client: Error(code) + "Permission denied"
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (11)
src/SecurityError.js (2)
13-28: Consider extracting the logger selection logic to reduce duplication.Both
createSanitizedErrorandcreateSanitizedHttpErrorcontain identical logic for selecting the logger. This violates the DRY principle and makes maintenance harder.Apply this diff to extract the common logic:
+/** + * Selects the appropriate logger from the provided parameter + * @param {Object} loggerOrConfig - Optional logger instance or config object + * @returns {Object} The selected logger instance + */ +function selectLogger(loggerOrConfig) { + if (loggerOrConfig) { + if (loggerOrConfig.loggerController) { + return loggerOrConfig.loggerController; + } else if (loggerOrConfig.error) { + return loggerOrConfig; + } + } + return defaultLogger; +} + export function createSanitizedError(errorCode, detailedMessage, loggerOrConfig = null) { - let log = defaultLogger; - if (loggerOrConfig) { - if (loggerOrConfig.loggerController) { - log = loggerOrConfig.loggerController; - } else if (loggerOrConfig.error) { - // It's a logger instance - log = loggerOrConfig; - } - } + const log = selectLogger(loggerOrConfig); // Keep log on server side log.error('Security error:', detailedMessage); return new Parse.Error(errorCode, 'Permission denied'); } export function createSanitizedHttpError(statusCode, detailedMessage, loggerOrConfig = null) { - let log = defaultLogger; - if (loggerOrConfig) { - if (loggerOrConfig.loggerController) { - log = loggerOrConfig.loggerController; - } else if (loggerOrConfig.error) { - log = loggerOrConfig; - } - } + const log = selectLogger(loggerOrConfig); // Keep log on server side log.error('Security error:', detailedMessage); const error = new Error(); error.status = statusCode; error.message = 'Permission denied'; return error; }Also applies to: 39-56
1-57: Suggest improved PR title following Angular commit convention.Based on learnings
The current PR title "feat: sanitize error for security" could be more descriptive and follow the Angular commit convention more precisely. Consider:
feat(security): sanitize error messages to prevent information disclosureThis title:
- Includes the scope (
security)- Clearly conveys the security improvement
- Makes a meaningful changelog entry for developers
src/Routers/FilesRouter.js (1)
8-9: Avoid double‑logging the security error ingetHandler
createSanitizedErroralready logs'Security error:'with the detailed message, so the explicitlog.error('Security error:', detailedError);causes duplicate log entries for the same event.You can rely on
createSanitizedError’s internal logging and drop both the explicit log call and the extra logger argument:-import { createSanitizedError } from '../SecurityError'; -import defaultLogger from '../logger'; +import { createSanitizedError } from '../SecurityError'; @@ if (!config) { res.status(403); - const detailedError = 'Invalid application ID.'; - const log = defaultLogger; - log.error('Security error:', detailedError); - const err = createSanitizedError(Parse.Error.OPERATION_FORBIDDEN, detailedError, log); + const detailedError = 'Invalid application ID.'; + const err = createSanitizedError(Parse.Error.OPERATION_FORBIDDEN, detailedError); res.json({ code: err.code, error: err.message }); return; }This keeps behavior the same (code + sanitized message) while logging only once.
Also applies to: 48-52
spec/ParseGraphQLServer.spec.js (1)
47-61: PR title: suggest Angular-style scoped variantTo make the changelog entry more informative and follow the Angular convention from this repo, consider updating the PR title to something like:
feat(security): sanitize permission error messagesThis reflects the security impact and the main behavior change more clearly.
src/RestQuery.js (1)
432-435: Use config-aware logger consistently when sanitizing errors in RestQuery
denyProtectedFieldscorrectly deriveslogfromthis.config.loggerController || defaultLogger, butvalidateClientClassCreationcurrently callscreateSanitizedErrorwithout passing any logger/config, so it always falls back to the global default.To keep logging consistent and app-scoped, consider:
- if (hasClass !== true) { - throw createSanitizedError( - Parse.Error.OPERATION_FORBIDDEN, - 'This user is not allowed to access ' + 'non-existent class: ' + this.className - ); - } + if (hasClass !== true) { + const detailedError = + 'This user is not allowed to access non-existent class: ' + this.className; + const log = (this.config && this.config.loggerController) || defaultLogger; + throw createSanitizedError( + Parse.Error.OPERATION_FORBIDDEN, + detailedError, + log + ); + }Also applies to: 811-816
src/triggers.js (1)
4-6: Validator now distinguishes security vs generic validation errorsThe updated
maybeRunValidatorlogic:
- Correctly treats
"Master key is required"and"Please login to continue"failures as security-sensitive, logging the detailed reason viadefaultLoggerand returning a genericVALIDATION_ERRORwith message'Permission denied'.- Preserves the existing
'Validation failed.'behavior for non-security validation problems.If you want to further centralize sanitization, you could consider reusing the shared helper instead of hand-rolling:
- if (isSecurityError) { - // Log detailed error server-side and sanitize for client - defaultLogger.error('Security validation error:', errorMessage); - error = resolveError(e, { - code: Parse.Error.VALIDATION_ERROR, - message: 'Permission denied', - }); - } else { + if (isSecurityError) { + defaultLogger.error('Security validation error:', errorMessage); + error = resolveError(e, { + code: Parse.Error.VALIDATION_ERROR, + message: 'Permission denied', + }); + } else {(or swap in
createSanitizedErrorif you decide to standardize on that helper for all security errors.)Also applies to: 696-735
src/RestWrite.js (1)
20-22: RestWrite sanitization is sound; consider minor logger and read-only consistency tweaksThe new sanitized error paths in RestWrite are functionally correct:
validateClientClassCreationand the unauthenticated_Userupdate guard now log detailed reasons via(this.config && this.config.loggerController) || defaultLoggerand expose only a generic permission error to clients.checkRestrictedFieldscorrectly blocks client-side updates toemailVerifiedwithOPERATION_FORBIDDEN.A few small follow-ups would make this file more consistent with the rest of the PR:
- Use the config-aware logger in
checkRestrictedFieldsRight now it relies on
createSanitizedError’s internal default logger. To align with the other call sites:if (!this.auth.isMaintenance && !this.auth.isMaster && 'emailVerified' in this.data) { - throw createSanitizedError(Parse.Error.OPERATION_FORBIDDEN, 'Clients aren\'t allowed to manually update email verification.'); + const log = (this.config && this.config.loggerController) || defaultLogger; + throw createSanitizedError( + Parse.Error.OPERATION_FORBIDDEN, + "Clients aren't allowed to manually update email verification.", + log + ); }
- Deduplicate logger imports
You currently import the same default export twice:
import logger from './logger'; import defaultLogger from './logger';You can keep just one default import and reuse it (e.g. stick with
loggerand dropdefaultLogger, or vice versa), which avoids confusion and potential lint warnings.
- Optional: sanitize the read-only masterKey constructor guard
The constructor still throws a raw
Parse.ErrormentioningreadOnlyMasterKey. Given thatSharedRest.enforceRoleSecurityshould block external read-only writes first, this is mostly an internal edge case, but you may still want to route it throughcreateSanitizedErrorfor consistency with other read-only enforcement paths.Also applies to: 191-216, 662-669, 1456-1463
src/SharedRest.js (3)
1-15: Configurable logger integration and signature change look correct; consider minor DRY refactor
- Importing
createSanitizedError/defaultLoggerand extendingenforceRoleSecurityto acceptconfig = nullis backward compatible and aligns with the new sanitization helper.- To avoid repeating
config || defaultLoggerin each branch, consider computing it once at the top of the function, e.g.const loggerOrConfig = config || defaultLogger;, and reuse it below.
17-20: Sanitized errors across all forbidden paths align with the security objective; optional helper could reduce duplication
- Each forbidden-operation path now builds a clear
detailedError, selectsloggerOrConfig, and throwscreateSanitizedError(Parse.Error.OPERATION_FORBIDDEN, …, loggerOrConfig), which should log server-side and return a generic “Permission denied” to clients—this matches the goal of not leaking details while preserving the error code.- The three branches share the same pattern; you could optionally factor a tiny local helper (or reuse a precomputed
loggerOrConfig) to reduce duplication and keep future changes to the sanitization behavior in one place.Also applies to: 29-31, 36-38
1-44: PR-level: title suggestion and documentation note for this security behavior change
- Given this is a security-focused behavioral change that developers should notice in the changelog, consider renaming the PR to an Angular-style title such as:
feat(security): sanitize permission errors- It may also be worth adding a short note to the security/docs/README explaining that certain authorization errors are now always surfaced as generic “Permission denied” while details are only logged server-side, so integrators know not to rely on error message text.
Based on learnings
src/Routers/SchemasRouter.js (1)
8-9: Sanitized error utilities imported correctly; minor DRY opportunity and PR title suggestionImports for
createSanitizedErroranddefaultLoggerlook good and match the shared helper pattern. To avoid repeating the same logger expression in multiple handlers, you could optionally introduce a small helper (e.g.const log = req.config?.loggerController || defaultLogger;) or passreq.configdirectly intocreateSanitizedErrorand let it resolve the logger internally, for slightly cleaner code.Side note for the PR itself: an Angular-style title that would read well in the changelog could be:
fix(security): sanitize read-only schema error messages
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (34)
spec/AudienceRouter.spec.js(5 hunks)spec/LogsRouter.spec.js(1 hunks)spec/ParseAPI.spec.js(1 hunks)spec/ParseFile.spec.js(3 hunks)spec/ParseGlobalConfig.spec.js(1 hunks)spec/ParseGraphQLServer.spec.js(7 hunks)spec/ParseInstallation.spec.js(1 hunks)spec/ParseQuery.Aggregate.spec.js(1 hunks)spec/ParseUser.spec.js(3 hunks)spec/RestQuery.spec.js(2 hunks)spec/Schema.spec.js(5 hunks)spec/features.spec.js(1 hunks)spec/rest.spec.js(11 hunks)spec/schemas.spec.js(10 hunks)spec/vulnerabilities.spec.js(1 hunks)src/Controllers/SchemaController.js(4 hunks)src/GraphQL/loaders/schemaMutations.js(4 hunks)src/GraphQL/loaders/schemaQueries.js(2 hunks)src/GraphQL/parseGraphQLUtils.js(1 hunks)src/RestQuery.js(5 hunks)src/RestWrite.js(4 hunks)src/Routers/ClassesRouter.js(2 hunks)src/Routers/FilesRouter.js(2 hunks)src/Routers/GlobalConfigRouter.js(2 hunks)src/Routers/GraphQLRouter.js(2 hunks)src/Routers/PurgeRouter.js(1 hunks)src/Routers/PushRouter.js(2 hunks)src/Routers/SchemasRouter.js(4 hunks)src/Routers/UsersRouter.js(2 hunks)src/SecurityError.js(1 hunks)src/SharedRest.js(3 hunks)src/middlewares.js(2 hunks)src/rest.js(6 hunks)src/triggers.js(2 hunks)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.824Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: Tests in the parse-server repository should use promise-based approaches rather than callback patterns with `done()`. Use a pattern where a Promise is created that resolves when the event occurs, then await that promise.
Applied to files:
spec/ParseInstallation.spec.jsspec/Schema.spec.jsspec/schemas.spec.jsspec/rest.spec.jsspec/ParseUser.spec.jsspec/vulnerabilities.spec.jsspec/RestQuery.spec.jsspec/ParseGraphQLServer.spec.jssrc/triggers.js
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`. The preferred pattern is to create a Promise that resolves when an expected event occurs, then await that Promise.
Applied to files:
spec/Schema.spec.jsspec/schemas.spec.jsspec/rest.spec.jsspec/ParseUser.spec.jsspec/vulnerabilities.spec.jsspec/RestQuery.spec.jsspec/ParseGraphQLServer.spec.jssrc/triggers.js
📚 Learning: 2025-05-04T20:41:05.147Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1312-1338
Timestamp: 2025-05-04T20:41:05.147Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`.
Applied to files:
spec/Schema.spec.jsspec/rest.spec.jsspec/ParseUser.spec.jsspec/vulnerabilities.spec.jsspec/RestQuery.spec.jsspec/ParseGraphQLServer.spec.jssrc/triggers.js
📚 Learning: 2025-11-08T13:46:04.940Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: For new Parse Server options, verify that the option is documented in src/Options/index.js and that npm run definitions has been executed to reflect changes in src/Options/docs.js and src/Options/Definitions.js. README.md documentation is a bonus but not required for new options.
Applied to files:
src/SharedRest.js
📚 Learning: 2025-09-21T15:43:32.265Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9858
File: src/GraphQL/ParseGraphQLServer.js:176-178
Timestamp: 2025-09-21T15:43:32.265Z
Learning: The GraphQL playground feature in ParseGraphQLServer.js (applyPlayground method) is intended for development environments only, which is why it includes the master key in client-side headers.
Applied to files:
src/GraphQL/loaders/schemaMutations.jssrc/Routers/GraphQLRouter.jssrc/GraphQL/parseGraphQLUtils.jsspec/ParseGraphQLServer.spec.js
📚 Learning: 2025-04-30T19:31:35.344Z
Learnt from: RahulLanjewar93
Repo: parse-community/parse-server PR: 9744
File: spec/ParseLiveQuery.spec.js:0-0
Timestamp: 2025-04-30T19:31:35.344Z
Learning: In the Parse Server codebase, the functions in QueryTools.js are typically tested through end-to-end behavior tests rather than direct unit tests, even though the functions are exported from the module.
Applied to files:
spec/rest.spec.jssrc/Routers/ClassesRouter.jsspec/RestQuery.spec.js
📚 Learning: 2025-08-27T12:33:06.237Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: src/triggers.js:467-477
Timestamp: 2025-08-27T12:33:06.237Z
Learning: In the Parse Server codebase, maybeRunAfterFindTrigger is called in production with Parse.Query objects constructed via withJSON(), so the plain object query handling bug only affects tests, not production code paths.
Applied to files:
spec/rest.spec.jssrc/RestQuery.js
📚 Learning: 2025-08-26T14:06:31.853Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: spec/CloudCode.spec.js:446-469
Timestamp: 2025-08-26T14:06:31.853Z
Learning: In the Parse Server codebase, when handling query objects in maybeRunAfterFindTrigger, objects without a where property that contain options like limit/skip should be treated as query JSON with an empty where clause using the spread pattern { where: {}, ...query }, not nested as { where: query }.
Applied to files:
src/RestQuery.js
📚 Learning: 2025-11-17T15:02:48.786Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
Applied to files:
spec/ParseGraphQLServer.spec.js
🧬 Code graph analysis (24)
src/SharedRest.js (3)
src/RestQuery.js (6)
require(7-7)require(9-9)require(10-10)defaultLogger(11-11)detailedError(125-125)detailedError(811-811)src/rest.js (4)
require(15-15)require(329-329)defaultLogger(330-330)detailedError(331-331)src/SecurityError.js (1)
createSanitizedError(13-28)
spec/schemas.spec.js (1)
src/Routers/SchemasRouter.js (2)
response(51-56)response(64-70)
src/GraphQL/loaders/schemaQueries.js (1)
src/GraphQL/parseGraphQLUtils.js (1)
enforceMasterKeyAccess(6-15)
src/GraphQL/loaders/schemaMutations.js (4)
src/GraphQL/parseGraphQLUtils.js (2)
enforceMasterKeyAccess(6-15)loggerOrConfig(8-8)src/middlewares.js (4)
enforceMasterKeyAccess(503-512)config(208-208)config(644-644)config(646-646)src/SharedRest.js (5)
loggerOrConfig(18-18)loggerOrConfig(30-30)loggerOrConfig(37-37)defaultLogger(11-11)Parse(1-1)src/SecurityError.js (1)
createSanitizedError(13-28)
src/Routers/GraphQLRouter.js (2)
src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)
src/SecurityError.js (6)
src/SharedRest.js (4)
loggerOrConfig(18-18)loggerOrConfig(30-30)loggerOrConfig(37-37)defaultLogger(11-11)src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/RestWrite.js (2)
log(205-205)log(1458-1458)src/Routers/SchemasRouter.js (3)
log(77-77)log(101-101)log(118-118)src/middlewares.js (8)
log(237-237)log(247-247)log(464-464)log(505-505)log(516-516)log(539-539)error(252-252)error(506-506)src/rest.js (2)
log(332-332)defaultLogger(330-330)
src/Routers/FilesRouter.js (3)
src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/SharedRest.js (2)
defaultLogger(11-11)Parse(1-1)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)
src/middlewares.js (1)
src/SecurityError.js (4)
log(14-14)log(40-40)error(52-52)createSanitizedHttpError(39-56)
src/Routers/ClassesRouter.js (1)
src/SecurityError.js (2)
log(14-14)createSanitizedError(13-28)
spec/features.spec.js (1)
src/middlewares.js (2)
error(252-252)error(506-506)
src/RestWrite.js (5)
src/RestQuery.js (5)
detailedError(125-125)detailedError(811-811)log(126-126)log(812-812)defaultLogger(11-11)src/SharedRest.js (5)
detailedError(17-17)detailedError(29-29)detailedError(36-36)defaultLogger(11-11)Parse(1-1)src/rest.js (3)
detailedError(331-331)log(332-332)defaultLogger(330-330)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)src/middlewares.js (6)
log(237-237)log(247-247)log(464-464)log(505-505)log(516-516)log(539-539)
src/Controllers/SchemaController.js (1)
src/SecurityError.js (1)
createSanitizedError(13-28)
src/GraphQL/parseGraphQLUtils.js (3)
src/middlewares.js (4)
enforceMasterKeyAccess(503-512)config(208-208)config(644-644)config(646-646)src/SharedRest.js (5)
loggerOrConfig(18-18)loggerOrConfig(30-30)loggerOrConfig(37-37)defaultLogger(11-11)Parse(1-1)src/SecurityError.js (1)
createSanitizedError(13-28)
src/RestQuery.js (4)
src/SharedRest.js (6)
require(10-10)defaultLogger(11-11)detailedError(17-17)detailedError(29-29)detailedError(36-36)Parse(1-1)src/rest.js (5)
require(15-15)require(329-329)defaultLogger(330-330)detailedError(331-331)log(332-332)src/middlewares.js (9)
config(208-208)config(644-644)config(646-646)log(237-237)log(247-247)log(464-464)log(505-505)log(516-516)log(539-539)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)
src/Routers/UsersRouter.js (7)
src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/RestWrite.js (2)
log(205-205)log(1458-1458)src/Routers/SchemasRouter.js (3)
log(77-77)log(101-101)log(118-118)src/SecurityError.js (2)
log(14-14)createSanitizedError(13-28)src/middlewares.js (6)
log(237-237)log(247-247)log(464-464)log(505-505)log(516-516)log(539-539)src/rest.js (2)
log(332-332)defaultLogger(330-330)src/SharedRest.js (2)
defaultLogger(11-11)Parse(1-1)
spec/AudienceRouter.spec.js (1)
src/middlewares.js (2)
error(252-252)error(506-506)
spec/ParseAPI.spec.js (1)
src/Routers/SchemasRouter.js (2)
response(51-56)response(64-70)
src/rest.js (3)
src/RestQuery.js (9)
className(1001-1001)require(7-7)require(9-9)require(10-10)defaultLogger(11-11)detailedError(125-125)detailedError(811-811)log(126-126)log(812-812)src/SecurityError.js (4)
error(52-52)log(14-14)log(40-40)createSanitizedError(13-28)src/SharedRest.js (6)
Parse(1-1)require(10-10)defaultLogger(11-11)detailedError(17-17)detailedError(29-29)detailedError(36-36)
src/Routers/PurgeRouter.js (1)
src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)
src/Routers/GlobalConfigRouter.js (2)
src/Routers/SchemasRouter.js (3)
log(77-77)log(101-101)log(118-118)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)
src/triggers.js (5)
src/Auth.js (2)
e(582-585)Parse(1-1)src/SecurityError.js (1)
error(52-52)src/middlewares.js (2)
error(252-252)error(506-506)src/RestQuery.js (1)
defaultLogger(11-11)src/SharedRest.js (2)
defaultLogger(11-11)Parse(1-1)
spec/ParseQuery.Aggregate.spec.js (1)
src/middlewares.js (2)
error(252-252)error(506-506)
src/Routers/SchemasRouter.js (4)
src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)src/middlewares.js (6)
log(237-237)log(247-247)log(464-464)log(505-505)log(516-516)log(539-539)src/rest.js (2)
log(332-332)defaultLogger(330-330)
src/Routers/PushRouter.js (2)
src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/SecurityError.js (3)
log(14-14)log(40-40)createSanitizedError(13-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
- GitHub Check: Node 18
- GitHub Check: Node 20
- GitHub Check: Node 22
- GitHub Check: MongoDB 8, ReplicaSet
- GitHub Check: MongoDB 7, ReplicaSet
- GitHub Check: Redis Cache
- GitHub Check: PostgreSQL 17, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.4
- GitHub Check: PostgreSQL 18, PostGIS 3.6
- GitHub Check: MongoDB 6, ReplicaSet
- GitHub Check: PostgreSQL 16, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.3
- GitHub Check: Code Analysis (javascript)
- GitHub Check: Docker Build
- GitHub Check: Benchmarks
🔇 Additional comments (24)
spec/LogsRouter.spec.js (1)
64-64: LGTM! Test expectation correctly updated.The error message expectation has been updated to align with the sanitized error handling. This test correctly verifies that unauthorized requests without a master key now receive the generic "Permission denied" message.
spec/ParseGlobalConfig.spec.js (1)
236-236: LGTM! Consistent with sanitized error handling.The test correctly expects "Permission denied" when attempting to update global config without the master key.
spec/vulnerabilities.spec.js (1)
18-18: LGTM! Error message appropriately generalized for security vulnerability.The test for GHSA-8xq9-g7ch-35hg (custom object ID privilege escalation vulnerability) now correctly expects "Permission denied" instead of "Invalid object ID." This generic message prevents leaking implementation details about the security check while maintaining the OPERATION_FORBIDDEN error code.
spec/features.spec.js (1)
35-35: LGTM! Test correctly updated for serverInfo endpoint.The test appropriately expects "Permission denied" when requesting serverInfo without the master key.
spec/ParseQuery.Aggregate.spec.js (1)
80-80: LGTM! Aggregate query error message correctly sanitized.The test correctly expects "Permission denied" for aggregate queries without master key authentication.
spec/ParseAPI.spec.js (1)
1727-1727: LGTM! Purge operation error correctly updated.The test appropriately expects "Permission denied" when attempting to purge objects without the master key.
spec/Schema.spec.js (1)
286-286: LGTM! All schema permission tests correctly updated.All test expectations have been consistently updated to "Permission denied" for:
- Count operations without permission (line 286)
- Required auth scenarios for find, create, get, and find operations (lines 1465, 1564, 1652, 1697)
These changes align with the sanitized error handling across permission-denied scenarios.
Also applies to: 1465-1465, 1564-1564, 1652-1652, 1697-1697
src/Routers/PurgeRouter.js (1)
4-5: Sanitized error for read‑only master key purge looks correctUsing
createSanitizedErrorwith(req.config && req.config.loggerController) || defaultLoggermatches the new security pattern and preserves the original error code while hiding details from clients.Also applies to: 10-15
src/Routers/UsersRouter.js (1)
19-21: Sanitized error for/loginAswithout master key is consistent
handleLogInAsnow routes the missing-master-key case throughcreateSanitizedErrorwith(req.config && req.config.loggerController) || defaultLogger, which matches the new security model and keeps the error code stable while generalizing the client‑facing message.Also applies to: 336-344
src/Routers/GraphQLRouter.js (1)
4-5: GraphQL config updates correctly use sanitized error for read‑only master keyFor read‑only master keys,
updateGraphQLConfignow throws acreateSanitizedErrorwithParse.Error.OPERATION_FORBIDDENand a logger derived fromreq.config.loggerControllerordefaultLogger, which aligns with the new permission‑denied semantics.Also applies to: 17-24
spec/rest.spec.js (1)
316-331: Tests correctly updated to expect sanitized'Permission denied'messagesThe affected tests still assert the correct Parse error codes (e.g.
OPERATION_FORBIDDEN) but now expect the generic'Permission denied'message for:
- Client‑class‑creation being disabled.
- Pointer reads into master‑key‑only classes (
_PushStatus,_GlobalConfig).- All
read-only masterKeywrite operations (REST, schemas, config, push).This matches the new sanitized error behavior while keeping codes stable for clients.
Also applies to: 772-786, 788-802, 945-989, 1024-1138
spec/RestQuery.spec.js (1)
157-172: RestQuery tests align with sanitized forbidden errorsBoth the disabled‑client‑class and protected‑field tests now assert the same error codes as before but with a generic
'Permission denied'message, which is consistent with the new sanitization logic.Also applies to: 216-248
src/Routers/ClassesRouter.js (1)
6-8: Sanitized error for invalid_UserobjectId (role:prefix) is appropriate
handleCreatenow rejects_Userobjects whoseobjectIdstarts with'role:'usingcreateSanitizedErrorand(req.config && req.config.loggerController) || defaultLogger, preserving the forbidden semantics while hiding the reason from clients.Also applies to: 110-119
spec/ParseUser.spec.js (1)
2634-2665: User/session tests correctly updated for generic permission errorsThe affected tests now:
- Keep their original error codes (e.g.
209for invalid/missing session token,OPERATION_FORBIDDENfor forbidden updates and/loginAswithout master key), and- Expect
'Permission denied'instead of more specific messages like'Session token required.',"Clients aren't allowed to manually update email verification.", or'master key is required'.This is consistent with the new sanitized error strategy and encourages clients to key off error codes rather than message text.
Also applies to: 3351-3384, 4374-4397
spec/ParseFile.spec.js (2)
159-159: LGTM! Security improvement correctly tested.The test expectations now correctly validate that generic "Permission denied" messages are returned for both missing and incorrect master key scenarios, preventing information disclosure about authentication requirements.
Also applies to: 172-172
763-763: LGTM! Error code preserved while message sanitized.The test correctly validates that error code 119 is maintained while the message is generalized from "Invalid application ID." to "Permission denied", preventing information disclosure about application IDs while preserving API contract.
spec/ParseGraphQLServer.spec.js (2)
3490-3505: Sanitized forbidden-error expectations are consistent with the new security modelAll updated assertions that now expect
Parse.Error.OPERATION_FORBIDDENwith the message'Permission denied'for class schema operations (create, update, delete, get, list) align with the PR goal of hiding authorization details while keeping codes stable. The tests remain precise and should fail if any endpoint accidentally reintroduces a more verbose error.Also applies to: 3841-3875, 4066-4100, 4126-4142, 4144-4160
6058-6125: Updated permission checks for object creation correctly target sanitized messagesThe
createObjectpermission tests now reject withjasmine.stringMatching('Permission denied')instead of a more detailed unauthorized message, which matches the sanitized error behavior while remaining resilient to small wording changes around that phrase. Looks good.src/GraphQL/parseGraphQLUtils.js (1)
3-13: Config-aware sanitized master-key enforcement looks correctUsing
createSanitizedErrorwithloggerOrConfig = config || defaultLoggerensures clients only see a generic permission error while detailed messages are logged via the app logger when available. The updatedenforceMasterKeyAccess(auth, config)signature is consistent with this pattern.src/RestQuery.js (1)
10-11: RestQuery master/session security sanitization is consistent
- Passing
configintoenforceRoleSecurityand usingcreateSanitizedErrorfor invalid session tokens ensures_Sessionaccess errors are logged with full detail while clients see a generic permission failure.- Use of
(this.config && this.config.loggerController) || defaultLoggerfor the session-token path matches the broader pattern introduced in this PR.Also applies to: 56-56, 122-132
src/Controllers/SchemaController.js (1)
23-24: CLP permission-denial sanitization preserves codes while hiding detailThe new
createSanitizedErrorusage inSchemaController.validatePermissioncorrectly:
- Keeps
OBJECT_NOT_FOUNDfor unauthenticated access andOPERATION_FORBIDDENfor CLP denials.- Logs detailed reasons via
defaultLoggerwhile only exposing a generic permission error to clients.This is consistent with the PR’s security objective and should not break code-based error handling.
Also applies to: 1408-1413, 1426-1428, 1447-1448
src/Routers/SchemasRouter.js (3)
76-82: Read‑only create‑schema error is now properly sanitized and loggedThe switch to
createSanitizedErrorpreserves theOPERATION_FORBIDDENcode, logs the detailed read‑only master key message via the resolved logger, and returns the generic client message. This matches the intended security behavior.
100-106: Consistent sanitized handling for schema updatesThe update path mirrors the create handler: same code, same detailed message confined to logs, and sanitized client error. The consistency across schema mutations is good.
118-123: Delete‑schema read‑only handling aligned with other mutationsThe delete handler now follows the same sanitized error pattern as create/update while keeping the forbidden error code. This keeps behavior uniform across all schema‑modifying operations.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## alpha #9937 +/- ##
==========================================
- Coverage 93.08% 93.08% -0.01%
==========================================
Files 187 188 +1
Lines 15275 15298 +23
Branches 177 177
==========================================
+ Hits 14219 14240 +21
- Misses 1044 1046 +2
Partials 12 12 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/SecurityError.js (3)
12-21: Make logger resolution more defensive and DRY.Both helpers duplicate the same logger resolution logic and treat any truthy
loggerOrConfig.erroras a logger, even if it’s not a function. That’s fine for the expectedconfig/ logger inputs, but it’s brittle for accidental misuse.Consider extracting a small
resolveLogger(loggerOrConfig)helper that:
- Returns
loggerOrConfig.loggerControllerwhen present.- Otherwise returns
loggerOrConfigonly iftypeof loggerOrConfig.error === 'function'.- Falls back to
defaultLoggerin all other cases.That removes duplication and avoids ever ending up with an object that doesn’t actually implement
error().Also applies to: 38-46
23-27: Optional: enrich server‑side logs with error code / status as metadata.Right now the log entry only includes the string message; the returned error carries the code/status, but that information is not in the log call itself. For security auditing and debugging it can be useful to log the numeric
errorCode/statusCodeas well (e.g. as an additional argument or metadata object), while still keeping the client message sanitized.This is not required for correctness, but worth considering for more informative security logs across the codebase.
Also applies to: 48-54
1-55: PR‑level: align title with Angular convention and consider documenting the new error behavior.Per the repo’s conventions, you may want to adjust the PR title to an Angular‑style variant that’s clearer in the changelog, for example:
feat(security): sanitize permission error responsesAlso, since this changes client‑visible error messages (even though codes stay the same), consider a short note in the README or upgrade notes explaining that certain security/permission errors now always return
"Permission denied"while detailed reasons are only available in server logs.src/SharedRest.js (1)
9-10: Access checks look correct; consider centralizing logger resolution.The refactor keeps the existing access rules intact while routing all denials through
createSanitizedError, which is exactly what we want for hiding detailed messages from clients and logging them server‑side. The newconfigparameter is optional, so existing callers remain valid and fall back todefaultLogger.You could optionally compute
const loggerOrConfig = config || defaultLogger;once near the top ofenforceRoleSecurityand reuse it in all three branches to avoid repetition, but that’s purely cosmetic and not required.Also applies to: 13-19, 28-31, 35-37
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/SecurityError.js(1 hunks)src/SharedRest.js(2 hunks)src/triggers.js(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.824Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.
🧬 Code graph analysis (2)
src/SharedRest.js (3)
src/RestQuery.js (6)
require(7-7)require(9-9)require(10-10)defaultLogger(11-11)detailedError(125-125)detailedError(811-811)src/rest.js (4)
require(15-15)require(329-329)defaultLogger(330-330)detailedError(331-331)src/SecurityError.js (1)
createSanitizedError(12-27)
src/SecurityError.js (4)
src/SharedRest.js (1)
defaultLogger(10-10)src/RestQuery.js (3)
log(126-126)log(812-812)defaultLogger(11-11)src/rest.js (2)
log(332-332)defaultLogger(330-330)src/middlewares.js (8)
log(237-237)log(247-247)log(464-464)log(505-505)log(516-516)log(539-539)error(252-252)error(506-506)
🪛 GitHub Check: Lint
src/triggers.js
[failure] 1112-1112:
Newline required at end of file but not found
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: PostgreSQL 18, PostGIS 3.6
- GitHub Check: PostgreSQL 16, PostGIS 3.5
- GitHub Check: PostgreSQL 17, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.4
- GitHub Check: PostgreSQL 15, PostGIS 3.3
- GitHub Check: PostgreSQL 15, PostGIS 3.5
- GitHub Check: Redis Cache
- GitHub Check: Node 22
- GitHub Check: Node 20
- GitHub Check: Node 18
- GitHub Check: MongoDB 8, ReplicaSet
- GitHub Check: MongoDB 7, ReplicaSet
- GitHub Check: MongoDB 6, ReplicaSet
- GitHub Check: Docker Build
- GitHub Check: Benchmarks
🔇 Additional comments (1)
src/triggers.js (1)
1-1112: Verify error sanitization scope in this file.The PR objective is to sanitize error messages for security. This file contains several error handling paths (e.g.,
resolveErrorat lines 669–693, validation error throws at lines 738–741, etc.) that could expose sensitive details. Per the AI summary, this file has "no observable functional changes" aside from the EOF newline.Please confirm whether error sanitization changes were intentionally omitted from
src/triggers.js, or if related changes are in other files within this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/rest.js (1)
171-173: Sanitize the early _User delete guard to align with the rest of the file.Line 172 still throws a raw
Parse.Error(Parse.Error.SESSION_MISSING, 'Insufficient auth to delete user'), exposing operation detail. This contradicts the sanitization applied tohandleSessionMissingErrorat lines 329-332.Apply this diff to sanitize the error:
if (className === '_User' && auth.isUnauthenticated()) { - throw new Parse.Error(Parse.Error.SESSION_MISSING, 'Insufficient auth to delete user'); + const { createSanitizedError } = require('./SecurityError'); + const detailedError = 'Insufficient auth to delete user'; + throw createSanitizedError(Parse.Error.SESSION_MISSING, detailedError); }Based on learnings
🧹 Nitpick comments (8)
src/GraphQL/parseGraphQLUtils.js (2)
5-12: Master-key enforcement now goes throughcreateSanitizedError; verify client message is actually sanitized.Routing this
OPERATION_FORBIDDENthroughcreateSanitizedErroris the right direction for centralizing and sanitizing permission errors, while preserving the error code. One thing to double‑check against #8958: ifcreateSanitizedErrorforwards itsmessageargument to the client unchanged, this would still expose"unauthorized: master key is required". In that case, either:
- have
createSanitizedErrorsanitize to a generic message (e.g."unauthorized"), or- pass a pre‑sanitized message here and log the detailed context inside
createSanitizedError.It would be good to have a GraphQL test asserting that the client no longer sees
"master key is required"in this path.
1-57: PR meta: Angular-style title suggestion and docs note.For the changelog, an Angular-style title that reflects this behavior change could be:
feat(security): sanitize permission errors for GraphQLAlso, since this subtly changes what clients see on authorization failures, consider a brief note in the README or security/operations docs (e.g., “detailed permission error messages are now logged server-side and hidden from clients”), even if no new option is added.
src/GraphQL/loaders/schemaMutations.js (1)
34-41: Read-only masterKey error is now sanitized in CreateClass.The implementation correctly uses
createSanitizedErrorto sanitize the error message. However, unlike similar changes in other files (e.g., src/RestWrite.js lines 204-210), this doesn't pass aconfig-aware logger. The error will still be sanitized, but detailed logging may use a default logger instead of the config's logger.If you want consistent logging with the config's logger, consider:
const { config, auth } = context; enforceMasterKeyAccess(auth, config); if (auth.isReadOnly) { + const log = (config && config.loggerController) || defaultLogger; throw createSanitizedError( Parse.Error.OPERATION_FORBIDDEN, "read-only masterKey isn't allowed to create a schema.", + log ); }(Same pattern applies to UpdateClass at lines 86-89 and DeleteClass at lines 137-140.)
src/Controllers/SchemaController.js (1)
1408-1413: Consider simplifying the error construction pattern.Per past review feedback, these could be more compact without the intermediate
detailedErrorvariable:if (!aclGroup || aclGroup.length == 0) { - const detailedError = 'Permission denied, user needs to be authenticated.'; - throw createSanitizedError(Parse.Error.OBJECT_NOT_FOUND, detailedError); + throw createSanitizedError( + Parse.Error.OBJECT_NOT_FOUND, + 'Permission denied, user needs to be authenticated.' + ); } else if (aclGroup.indexOf('*') > -1 && aclGroup.length == 1) { - const detailedError = 'Permission denied, user needs to be authenticated.'; - throw createSanitizedError(Parse.Error.OBJECT_NOT_FOUND, detailedError); + throw createSanitizedError( + Parse.Error.OBJECT_NOT_FOUND, + 'Permission denied, user needs to be authenticated.' + ); }This same pattern applies to lines 1426-1427 and 1447-1448 as well.
Based on learnings
src/RestWrite.js (2)
667-669: Good: compact error construction pattern.The single-line
createSanitizedErrorcall is concise and readable, though it doesn't pass a config-aware logger like the implementation at lines 204-210.For consistency with line 205, consider passing a config-aware logger:
- if (!this.auth.isMaintenance && !this.auth.isMaster && 'emailVerified' in this.data) { - throw createSanitizedError(Parse.Error.OPERATION_FORBIDDEN, 'Clients aren\'t allowed to manually update email verification.'); + if (!this.auth.isMaintenance && !this.auth.isMaster && 'emailVerified' in this.data) { + const log = (this.config && this.config.loggerController) || defaultLogger; + throw createSanitizedError( + Parse.Error.OPERATION_FORBIDDEN, + 'Clients aren\'t allowed to manually update email verification.', + log + ); }
1456-1462: User modification error is sanitized, but logger parameter could be added.The implementation correctly uses
createSanitizedError, but unlike the pattern at lines 204-210, it doesn't pass a config-aware logger.For consistency, consider:
if (this.className === '_User' && this.query && this.auth.isUnauthenticated()) { const detailedError = `Cannot modify user ${this.query.objectId}.`; + const log = (this.config && this.config.loggerController) || defaultLogger; throw createSanitizedError( Parse.Error.SESSION_MISSING, detailedError, + log ); }src/Routers/PushRouter.js (2)
13-16: Sanitized error use looks correct; optionally align logging and testsUsing
createSanitizedErrorwithParse.Error.OPERATION_FORBIDDENhere keeps the error code stable while delegating message sanitization, which matches the objective of hiding detailed authorization reasons from clients.Two optional follow-ups:
- If
createSanitizedErrorsupports receiving a logger or request context, consider passing inreq.config.loggerController(or a derived logger) so read-only masterKey misuse on/pushis logged consistently with other sanitized errors in this PR.- Ensure there is a test that exercises this read-only
masterKeypath and asserts the generic client-facing message while still preserving the correct error code.
1-85: PR title & documentation suggestionTo make the changelog clearer and follow Angular-style conventions, consider renaming the PR to something like:
feat(security): sanitize unauthorized error messagesAlso consider a brief note in the changelog (or README, if you think it affects integrators) that certain security-related errors now return generic client messages while logging detailed diagnostics server-side, so users understand why previously detailed messages have become more generic.
Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
src/Controllers/SchemaController.js(4 hunks)src/GraphQL/loaders/schemaMutations.js(4 hunks)src/GraphQL/parseGraphQLUtils.js(1 hunks)src/RestQuery.js(5 hunks)src/RestWrite.js(4 hunks)src/Routers/ClassesRouter.js(2 hunks)src/Routers/FilesRouter.js(2 hunks)src/Routers/GlobalConfigRouter.js(2 hunks)src/Routers/GraphQLRouter.js(2 hunks)src/Routers/PurgeRouter.js(1 hunks)src/Routers/PushRouter.js(2 hunks)src/Routers/SchemasRouter.js(4 hunks)src/Routers/UsersRouter.js(2 hunks)src/SecurityError.js(1 hunks)src/SharedRest.js(2 hunks)src/middlewares.js(2 hunks)src/rest.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
- src/Routers/SchemasRouter.js
- src/Routers/GraphQLRouter.js
- src/Routers/ClassesRouter.js
- src/Routers/UsersRouter.js
- src/Routers/FilesRouter.js
- src/RestQuery.js
- src/Routers/PurgeRouter.js
- src/SecurityError.js
- src/Routers/GlobalConfigRouter.js
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.824Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.
📚 Learning: 2025-09-21T15:43:32.265Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9858
File: src/GraphQL/ParseGraphQLServer.js:176-178
Timestamp: 2025-09-21T15:43:32.265Z
Learning: The GraphQL playground feature in ParseGraphQLServer.js (applyPlayground method) is intended for development environments only, which is why it includes the master key in client-side headers.
Applied to files:
src/GraphQL/loaders/schemaMutations.jssrc/GraphQL/parseGraphQLUtils.js
🔇 Additional comments (6)
src/GraphQL/parseGraphQLUtils.js (1)
3-3: Import ofcreateSanitizedErrorlooks correct and aligns with new security helper.The import cleanly plugs this module into the centralized security error handling without changing the public API.
src/rest.js (1)
329-332: LGTM! Session missing error is now sanitized.The implementation correctly uses
createSanitizedErrorto sanitize the error message while preserving the error code and detailed message for server-side logging.src/middlewares.js (1)
503-518: LGTM! Master key enforcement is now sanitized.Both
enforceMasterKeyAccessandpromiseEnforceMasterKeyAccesscorrectly usecreateSanitizedHttpErrorto sanitize the error response while preserving the detailed message for server-side logging.src/SharedRest.js (1)
12-35: LGTM! Role security errors are now sanitized.All three error paths in
enforceRoleSecuritycorrectly usecreateSanitizedErrorto sanitize error messages while preserving detailed error information for server-side logging. The implementation is consistent and maintains the original control flow.src/RestWrite.js (1)
204-210: LGTM! Client class creation error is sanitized with config-aware logging.The implementation correctly uses
createSanitizedErrorwith a config-aware logger, ensuring detailed errors are logged to the configured logger while sending sanitized messages to clients.src/Routers/PushRouter.js (1)
4-4: createSanitizedError import integrates PushRouter into the sanitization layerImporting
createSanitizedErrorhere is appropriate and keeps push routing aligned with the centralized error-sanitization helper; no issues from a dependency or routing perspective.
|
@coratgerl you can treat coderabbit review comments like human review comments; if you followed it, coderabbit will close its comment after checking your next commit. you should only resolve it manually after providing your arguments. if in doubt you can engage in a discussion. That makes it easier for everyone to know what your position on the feedback is. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
spec/schemas.spec.js (1)
2513-2605: Fix mismatched action name in CLP 5 sanitized log expectationIn
validate CLP 5, the first forbidden query is afind()call, but the sanitized log expectation usesaction create:sanitizedErrorCall.checkMessage( 'Permission denied for action create on class AClass', callCountBefore );Given this branch is exercising a
findoperation, the detailed message should stay aligned with the other CLP tests and the underlying enforcement.- sanitizedErrorCall.checkMessage('Permission denied for action create on class AClass', callCountBefore); + sanitizedErrorCall.checkMessage('Permission denied for action find on class AClass', callCountBefore);Without this, the test is likely to fail or become misleading if the implementation correctly reports
findas the action.
♻️ Duplicate comments (2)
src/RestWrite.js (1)
1458-1462: Verify logger usage consistency (same concern as line 666).Similar to the comment at line 666, this
createSanitizedErrorcall doesn't pass a logger parameter, while the call at line 205 does. Ensure this is intentional and that the detailed error message (includingthis.query.objectId) is properly logged server-side.src/rest.js (1)
171-176: Unauthenticated_Userdelete still throws raw error, bypassing sanitization helperThe early guard:
if (className === '_User' && auth.isUnauthenticated()) { throw new Parse.Error(Parse.Error.SESSION_MISSING, 'Insufficient auth to delete user'); }still sends a detailed message directly to the client instead of going through
createSanitizedError, which is inconsistent with the new sanitized session/auth handling and the behavior inhandleSessionMissingError.To fully align delete‑user with the sanitization strategy, route this branch through
createSanitizedErroras well:if (className === '_User' && auth.isUnauthenticated()) { - throw new Parse.Error(Parse.Error.SESSION_MISSING, 'Insufficient auth to delete user'); + const { createSanitizedError } = require('./Error'); + throw createSanitizedError( + Parse.Error.SESSION_MISSING, + 'Insufficient auth to delete user' + ); }(Alternatively, you could delegate to
handleSessionMissingErrorif you prefer a single central helper.)This avoids leaking operation details to clients while keeping richer information in the server logs.
🧹 Nitpick comments (10)
src/TestUtils.js (1)
85-104: Make logger spy resilient to repeated usage and tightly-coupled prefixThe helper works for current tests, but it assumes
spyOn(logger, 'error')is only ever called once per spec and that tests always run withprocess.env.TESTINGset so the first log arg is exactly'Sanitized error:'. If a spec callsgetSanitizedErrorCall()twice on the same logger, Jasmine may throw for double-spying unlessallowRespy(true)is configured, and any future change to the prefix would silently break all these tests.To make this more robust, consider:
- Reusing an existing spy if one already exists instead of always calling
spyOn.- Centralizing the
'Sanitized error:'prefix (e.g. exported constant fromsrc/Error.js) so tests and implementation cannot drift.spec/AudienceRouter.spec.js (1)
5-5: AudienceRouter master-key tests comprehensively validate sanitized errorsAll push_audiences authorization tests now assert a generic
'Permission denied'on the client and usegetSanitizedErrorCallto confirm the detailed master-key message was logged, covering POST/GET/PUT/DELETE consistently. This is a solid, end‑to‑end check of the new sanitization behavior.Also applies to: 266-339
spec/ParseFile.spec.js (1)
766-776: Tidy TestUtils import and confirm unauthorized file-path behaviorTwo small points here:
Inside
"does not crash on file request with invalid app ID", you re-require('../lib/TestUtils')and destructuregetSanitizedErrorCall, even though it is already imported at the top of the file. You can use the existing import and drop the inlinerequireto avoid redundancy.For invalid file paths, the test still expects
{ error: 'unauthorized' }instead of the generic'Permission denied'used for invalid application IDs. If the goal is that all unauthorized file routes share the same sanitized client message, it may be worth aligning this case as well; otherwise, clarifying in a comment or issue which cases are deliberately left as'unauthorized'could prevent confusion later.Also applies to: 782-788
src/Error.js (1)
1-44: Centralized sanitization helpers look good; consider minor hardening and docs/changelogThe new helpers encapsulate the pattern of:
- Logging the detailed message via
defaultLogger.error(...), with a'Sanitized error:'prefix underTESTINGso specs can detect it.- Returning a
Parse.Erroror plainErrorthat always exposes the generic'Permission denied'string while preserving the original error or HTTP status code.A few small follow‑ups to consider:
- Avoid duplicate logging logic: Extract a small internal helper (e.g.
logSanitizedError(detailedMessage)) shared by both functions to keep the logging behavior in one place and reduce drift risk if the format ever changes.- Be explicit about Parse dependency: If feasible within this codebase’s conventions, importing
Parse(rather than relying on a global) would makecreateSanitizedErrormore self‑contained and tooling‑friendly.- Lock in the test contract: The tests rely on the
'Sanitized error:'prefix only being used inTESTING. If any other code path ever starts logging with that same prefix, the TestUtils helper may get false positives; conversely, changing the prefix will break many specs. It may be worth documenting this contract in a short comment near the export or in CONTRIBUTING.Given this is a security‑relevant behavior change visible to clients, please also:
Add or update a short note in the appropriate docs/README or migration/changelog area to mention that certain authorization failures now return a generic
"Permission denied"message while keeping error codes unchanged.Update the PR title to an Angular-style form suitable for the changelog, for example:
feat(security): sanitize unauthorized error messagessrc/RestWrite.js (1)
204-209: Consider using optional chaining for consistency.The logger retrieval works correctly, but for consistency with the patterns in
src/middlewares.js(lines 236, 246, 463, 536), consider using optional chaining:Apply this diff:
- const log = (this.config && this.config.loggerController) || defaultLogger; + const log = this.config?.loggerController || defaultLogger;spec/schemas.spec.js (2)
7-8: Avoid double requiring../lib/TestUtilsYou now import
../lib/TestUtilstwice (asTestUtilsand via destructuring). To keep things consistent with other specs (e.g.spec/ParseAPI.spec.js) and avoid redundancy, consider a single destructured import:-const TestUtils = require('../lib/TestUtils'); -const { getSanitizedErrorCall } = require('../lib/TestUtils'); +const { destroyAllDataPermanently, getSanitizedErrorCall } = require('../lib/TestUtils');and then call
destroyAllDataPermanentlydirectly where needed.
170-190: Strengthen schema auth tests by asserting error code as wellThese two tests now correctly assert the sanitized message
'Permission denied', but they still rely only on status + message. To better pin down the behavior of the sanitized error, also assert the error code (e.g.Parse.Error.OPERATION_FORBIDDEN) in both tests.}).then(fail, response => { expect(response.status).toEqual(403); - expect(response.data.error).toEqual('Permission denied'); + expect(response.data.code).toEqual(Parse.Error.OPERATION_FORBIDDEN); + expect(response.data.error).toEqual('Permission denied');Apply the same pattern to the following test that covers
/schemaswith REST key.spec/Schema.spec.js (1)
1449-1727: Consider asserting error codes in required-auth tests as wellThe required-auth tests (
find,create,get,find not authenticated) now:
- Assert the generic
'Permission denied'message.- Use
getSanitizedErrorCallto verify the detailed log message'Permission denied, user needs to be authenticated.'.To further harden these tests against regressions, you may want to also assert the error code (e.g.,
Parse.Error.OPERATION_FORBIDDEN) alongside the message in each of these cases, similar to the CLP tests above.- e => { - expect(e.message).toEqual('Permission denied'); + e => { + expect(e.code).toEqual(Parse.Error.OPERATION_FORBIDDEN); + expect(e.message).toEqual('Permission denied'); sanitizedErrorCall.checkMessage( 'Permission denied, user needs to be authenticated.', callCountBefore );This is optional but would make the required-auth suite consistent with the other permission tests.
spec/ParseAPI.spec.js (1)
1713-1733: Purge-without-master-key test correctly exercises sanitized error; consider tightening assertionsThe updated test now:
- Uses
getSanitizedErrorCallandcallCountBefore.- Asserts the client-facing
response.data.erroris'Permission denied'.- Verifies the logged detailed message contains
'unauthorized: master key is required'.To fully specify the behavior, you could also assert the HTTP status and/or error code, e.g.:
.catch(response => { - expect(response.data.error).toEqual('Permission denied'); + expect(response.status).toBe(403); + expect(response.data.code).toBe(Parse.Error.OPERATION_FORBIDDEN); + expect(response.data.error).toEqual('Permission denied'); sanitizedErrorCall.checkMessage( 'unauthorized: master key is required', callCountBefore );Not required, but this would make the test more robust.
src/Routers/GraphQLRouter.js (1)
4-24: Read‑only master key now returns a sanitized forbidden error for GraphQL config updatesUsing:
throw createSanitizedError( Parse.Error.OPERATION_FORBIDDEN, "read-only masterKey isn't allowed to update the GraphQL config.", );on
req.auth.isReadOnlyensures:
- Clients only see a generic “Permission denied” (via the helper).
- Logs still carry the detailed reason, matching the rest of the sanitization work.
For the changelog, an Angular-style PR title that reflects this broader change could be:
feat(security): sanitize permission errors
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (31)
spec/AudienceRouter.spec.js(2 hunks)spec/LogsRouter.spec.js(3 hunks)spec/ParseAPI.spec.js(5 hunks)spec/ParseFile.spec.js(6 hunks)spec/ParseGlobalConfig.spec.js(3 hunks)spec/ParseGraphQLServer.spec.js(12 hunks)spec/ParseQuery.Aggregate.spec.js(2 hunks)spec/ParseUser.spec.js(8 hunks)spec/RestQuery.spec.js(3 hunks)spec/Schema.spec.js(15 hunks)spec/features.spec.js(3 hunks)spec/rest.spec.js(12 hunks)spec/schemas.spec.js(19 hunks)src/Controllers/SchemaController.js(4 hunks)src/Error.js(1 hunks)src/GraphQL/loaders/schemaMutations.js(4 hunks)src/GraphQL/parseGraphQLUtils.js(1 hunks)src/RestQuery.js(5 hunks)src/RestWrite.js(4 hunks)src/Routers/ClassesRouter.js(2 hunks)src/Routers/FilesRouter.js(2 hunks)src/Routers/GlobalConfigRouter.js(2 hunks)src/Routers/GraphQLRouter.js(2 hunks)src/Routers/PurgeRouter.js(1 hunks)src/Routers/PushRouter.js(2 hunks)src/Routers/SchemasRouter.js(4 hunks)src/Routers/UsersRouter.js(2 hunks)src/SharedRest.js(2 hunks)src/TestUtils.js(1 hunks)src/middlewares.js(2 hunks)src/rest.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (16)
- src/Routers/FilesRouter.js
- src/Routers/PurgeRouter.js
- src/middlewares.js
- src/Routers/SchemasRouter.js
- spec/ParseQuery.Aggregate.spec.js
- spec/RestQuery.spec.js
- spec/rest.spec.js
- src/Controllers/SchemaController.js
- src/SharedRest.js
- spec/features.spec.js
- src/RestQuery.js
- src/GraphQL/loaders/schemaMutations.js
- spec/ParseGraphQLServer.spec.js
- src/Routers/ClassesRouter.js
- src/GraphQL/parseGraphQLUtils.js
- src/Routers/GlobalConfigRouter.js
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.824Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.
📚 Learning: 2025-09-21T15:43:32.265Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9858
File: src/GraphQL/ParseGraphQLServer.js:176-178
Timestamp: 2025-09-21T15:43:32.265Z
Learning: The GraphQL playground feature in ParseGraphQLServer.js (applyPlayground method) is intended for development environments only, which is why it includes the master key in client-side headers.
Applied to files:
src/Routers/GraphQLRouter.js
📚 Learning: 2025-10-16T19:27:05.311Z
Learnt from: Moumouls
Repo: parse-community/parse-server PR: 9883
File: spec/CloudCodeLogger.spec.js:410-412
Timestamp: 2025-10-16T19:27:05.311Z
Learning: In spec/CloudCodeLogger.spec.js, the test "should log cloud function triggers using the silent log level" (around lines 383-420) is known to be flaky and requires the extra `await new Promise(resolve => setTimeout(resolve, 100))` timeout after awaiting `afterSavePromise` for reliability, even though it may appear redundant.
Applied to files:
spec/AudienceRouter.spec.jsspec/schemas.spec.jsspec/ParseUser.spec.jsspec/LogsRouter.spec.jsspec/Schema.spec.js
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: Tests in the parse-server repository should use promise-based approaches rather than callback patterns with `done()`. Use a pattern where a Promise is created that resolves when the event occurs, then await that promise.
Applied to files:
spec/AudienceRouter.spec.jsspec/schemas.spec.jsspec/ParseUser.spec.jsspec/Schema.spec.jsspec/ParseAPI.spec.js
📚 Learning: 2025-05-04T20:41:05.147Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1312-1338
Timestamp: 2025-05-04T20:41:05.147Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`.
Applied to files:
spec/AudienceRouter.spec.jsspec/schemas.spec.jsspec/ParseUser.spec.jsspec/Schema.spec.jsspec/ParseAPI.spec.js
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`. The preferred pattern is to create a Promise that resolves when an expected event occurs, then await that Promise.
Applied to files:
spec/AudienceRouter.spec.jsspec/schemas.spec.jsspec/ParseUser.spec.jsspec/Schema.spec.jsspec/ParseAPI.spec.js
📚 Learning: 2025-04-30T19:31:35.344Z
Learnt from: RahulLanjewar93
Repo: parse-community/parse-server PR: 9744
File: spec/ParseLiveQuery.spec.js:0-0
Timestamp: 2025-04-30T19:31:35.344Z
Learning: In the Parse Server codebase, the functions in QueryTools.js are typically tested through end-to-end behavior tests rather than direct unit tests, even though the functions are exported from the module.
Applied to files:
spec/AudienceRouter.spec.jsspec/schemas.spec.jsspec/Schema.spec.jsspec/ParseAPI.spec.js
📚 Learning: 2025-08-27T12:33:06.237Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: src/triggers.js:467-477
Timestamp: 2025-08-27T12:33:06.237Z
Learning: In the Parse Server codebase, maybeRunAfterFindTrigger is called in production with Parse.Query objects constructed via withJSON(), so the plain object query handling bug only affects tests, not production code paths.
Applied to files:
spec/schemas.spec.jsspec/Schema.spec.js
📚 Learning: 2025-08-27T09:08:34.252Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: src/triggers.js:446-454
Timestamp: 2025-08-27T09:08:34.252Z
Learning: When analyzing function signature changes in Parse Server codebase, verify that call sites are actually incorrect before flagging them. Passing tests are a strong indicator that function calls are already properly aligned with new signatures.
Applied to files:
spec/ParseUser.spec.jsspec/ParseAPI.spec.js
🧬 Code graph analysis (12)
src/rest.js (1)
src/RestQuery.js (3)
require(7-7)require(9-9)require(10-10)
src/TestUtils.js (3)
spec/ParseLiveQuery.spec.js (4)
logger(299-299)logger(589-589)logger(632-632)require(8-8)spec/ParseAPI.spec.js (1)
require(9-9)spec/ParseConfigKey.spec.js (1)
loggerErrorSpy(5-5)
src/Error.js (2)
src/RestQuery.js (1)
defaultLogger(11-11)src/middlewares.js (2)
error(252-252)error(505-505)
spec/AudienceRouter.spec.js (2)
src/TestUtils.js (1)
getSanitizedErrorCall(85-104)src/middlewares.js (2)
error(252-252)error(505-505)
spec/schemas.spec.js (1)
src/TestUtils.js (1)
getSanitizedErrorCall(85-104)
spec/ParseGlobalConfig.spec.js (1)
src/TestUtils.js (1)
getSanitizedErrorCall(85-104)
spec/ParseUser.spec.js (1)
src/TestUtils.js (1)
getSanitizedErrorCall(85-104)
spec/LogsRouter.spec.js (1)
src/TestUtils.js (1)
getSanitizedErrorCall(85-104)
spec/Schema.spec.js (2)
spec/ParseAPI.spec.js (2)
require(9-9)Parse(6-6)src/TestUtils.js (1)
getSanitizedErrorCall(85-104)
src/RestWrite.js (2)
src/middlewares.js (4)
log(237-237)log(247-247)log(464-464)log(537-537)src/RestQuery.js (1)
defaultLogger(11-11)
spec/ParseAPI.spec.js (1)
src/TestUtils.js (2)
destroyAllDataPermanently(8-28)getSanitizedErrorCall(85-104)
spec/ParseFile.spec.js (2)
spec/ParseAPI.spec.js (1)
require(9-9)src/TestUtils.js (1)
getSanitizedErrorCall(85-104)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: Docker Build
- GitHub Check: Benchmarks
- GitHub Check: Node 22
- GitHub Check: PostgreSQL 18, PostGIS 3.6
- GitHub Check: PostgreSQL 17, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.3
- GitHub Check: Node 18
- GitHub Check: Node 20
- GitHub Check: PostgreSQL 16, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.5
- GitHub Check: PostgreSQL 15, PostGIS 3.4
- GitHub Check: Redis Cache
- GitHub Check: MongoDB 8, ReplicaSet
- GitHub Check: MongoDB 6, ReplicaSet
- GitHub Check: MongoDB 7, ReplicaSet
🔇 Additional comments (18)
spec/LogsRouter.spec.js (1)
4-5: LogsRouter master-key test correctly validates sanitized vs logged detailThe updated test now asserts the client sees a generic
403/'Permission denied'while also verifying that the logger captured'unauthorized: master key is required'viagetSanitizedErrorCall, which is exactly what this PR aims for.Also applies to: 55-70
spec/ParseGlobalConfig.spec.js (1)
5-5: GlobalConfig master-key test aligns with sanitized error behaviorThe test now correctly expects a generic
'Permission denied'on the client while asserting that the logger recorded'unauthorized: master key is required'usinggetSanitizedErrorCall, matching the new sanitization contract.Also applies to: 223-242
spec/ParseUser.spec.js (4)
15-15: New TestUtils import is appropriate for user-related security testsImporting
getSanitizedErrorCallhere is appropriate, as multiple user/session flows now verify that detailed messages are logged while clients receive only sanitized text.
2635-2670: Confirm intent to sanitize this specific invalid-session-token REST pathIn
it('cannot delete session if no sessionToken'), the firstPUT /sessions/:idwith an invalid session token now returns'Permission denied'(code 209), while the test asserts the detailed'Invalid session token'message is only present in the logs viagetSanitizedErrorCall.Elsewhere in this file, some flows (e.g. "Invalid session tokens are rejected") still expect the full
'Invalid session token'text in the HTTP response. Please confirm that this asymmetry is intentional (RESTPUT /sessions/:idsanitized, other session-token checks not) and not a missed conversion.
3363-3394: Email-verification test correctly distinguishes client vs logged messagesThe
"should not allow updates to emailVerified"test now:
- Installs a sanitized logger spy after reconfiguration.
- Expects the client error message
'Permission denied'.- Verifies the logged detail
"Clients aren't allowed to manually update email verification.".This precisely exercises the new sanitization helper and protects against regressions in the sensitive email-verification path.
4387-4413: loginAs master-key test is well-aligned with sanitized HTTP errorsFor
loginAswithout master key, the test now:
- Tracks sanitized logger calls with
getSanitizedErrorCall.- Expects
OPERATION_FORBIDDENwith client message'Permission denied'.- Asserts the logged detail contains
'master key is required'.Using a substring for the logged message (
toContain) gives some flexibility if the detailed text is extended, while still verifying that the critical part is logged.spec/ParseFile.spec.js (1)
8-8: File deletion tests now robustly cover sanitized master-key errorsThe "blocks file deletions with missing or incorrect master-key header" test:
- Correctly expects
403 / 'Permission denied'for both missing and wrong master key.- Uses
getSanitizedErrorCallwith separatecallCountBeforevalues to assert that detailed'unauthorized: master key is required'messages were logged for each attempt.This gives strong coverage of both branches of the authorization check.
Also applies to: 135-184
src/RestWrite.js (2)
20-21: LGTM!The import statements are correct and follow the same pattern used in other files like
src/middlewares.jsandsrc/RestQuery.js.
666-669: ****The function signature for
createSanitizedError(src/Error.js:11) accepts only 2 parameters:errorCodeanddetailedMessage. The call at line 205 does not pass a logger parameter—it only passes 2 parameters, identical to line 666. All 26+ usages throughout the codebase consistently use 2 parameters only. The code is correct and consistent; no changes are needed.Likely an incorrect or invalid review comment.
spec/schemas.spec.js (2)
1811-1844: Good coverage of sanitized CLP error for addFieldThis test now:
- Asserts the client-facing message
'Permission denied'.- Verifies
err.code === Parse.Error.OPERATION_FORBIDDEN.- Uses
getSanitizedErrorCallto assert the detailed log message ('Permission denied for action addField on class AClass').That combination exercises both the sanitized surface and the logged detail as intended.
2175-2511: CLP find tests now validate both error code and sanitized logThe
validate CLP 1–4tests correctly:
- Capture the logger error call count before the forbidden query.
- Assert the thrown error has message
'Permission denied'and codeParse.Error.OPERATION_FORBIDDEN.- Assert the logged detailed message uses the correct action (
find) and class name.This matches the new sanitized error behavior and addresses the previous request to also test the error code.
spec/Schema.spec.js (2)
5-5: ImportinggetSanitizedErrorCallhere is appropriatePulling
getSanitizedErrorCallfrom../lib/TestUtilsmatches how other specs hook into the sanitized error logger and keeps this file aligned with the new test utilities.
252-297: CLPcounttest now fully validates sanitized error behaviorThe updated
class-level permissions test count:
- Captures logger call count before the forbidden
query.count().- Asserts
err.message === 'Permission denied'.- Asserts
err.code === Parse.Error.OPERATION_FORBIDDEN.- Verifies the logged detailed message (
'Permission denied for action count on class Stuff').This is a solid end-to-end check of both the client-visible and logged aspects of the sanitized error.
spec/ParseAPI.spec.js (2)
9-9: Destructured TestUtils import is clearer and consistentSwitching to:
const { getSanitizedErrorCall, destroyAllDataPermanently } = require('../lib/TestUtils');simplifies call sites and matches the pattern used elsewhere in the suite.
164-208:destroyAllDataPermanently()usage remains correct after refactorThese tests now call
destroyAllDataPermanently()directly instead of viaTestUtils., while preserving the same promise chain. Behavior and semantics remain unchanged.src/Routers/PushRouter.js (1)
11-21: Push with read‑only master key now uses sanitized permission errorThe new guard:
if (req.auth.isReadOnly) { throw createSanitizedError( Parse.Error.OPERATION_FORBIDDEN, "read-only masterKey isn't allowed to send push notifications.", ); }correctly routes this case through the sanitization helper, so clients see a generic forbidden error while logs retain detail.
src/rest.js (1)
321-332: Session‑missing path for_Usernow sanitized throughcreateSanitizedError
handleSessionMissingErrornow transforms an_UserOBJECT_NOT_FOUNDunder non‑master auth into:const { createSanitizedError } = require('./Error'); throw createSanitizedError(Parse.Error.SESSION_MISSING, 'Insufficient auth.');This keeps the error code (
SESSION_MISSING) while ensuring the client only sees the generic sanitized message, with the detailed context available in logs.src/Routers/UsersRouter.js (1)
335-373:/loginAsnow correctly uses sanitized permission error for non‑master callsThe updated guard:
if (!req.auth.isMaster) { throw createSanitizedError( Parse.Error.OPERATION_FORBIDDEN, 'master key is required', ); }ensures
/loginAs:
- Still enforces master‑key only access.
- Returns a sanitized forbidden error to clients, while logging the specific reason, in line with the rest of the sanitization work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/RestWrite.js (1)
1-1861: Consider improving the PR title per Angular commit convention.Based on learnings, the PR title should follow the Angular commit convention format (
type(scope): description) and make a meaningful changelog entry for developers.Current title:
feat: Sanitize error for securitySuggested improvement:
fix(security): sanitize authorization error messages to prevent information disclosureThis better conveys that:
- It's a security fix (not a new feature)
- It addresses information disclosure
- It's specifically about authorization errors
- It provides value as a changelog entry
Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/RestQuery.js(5 hunks)src/RestWrite.js(5 hunks)src/rest.js(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/rest.js
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
📚 Learning: 2025-08-27T09:08:34.252Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: src/triggers.js:446-454
Timestamp: 2025-08-27T09:08:34.252Z
Learning: When analyzing function signature changes in Parse Server codebase, verify that call sites are actually incorrect before flagging them. Passing tests are a strong indicator that function calls are already properly aligned with new signatures.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-11-08T13:46:04.940Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-11-17T15:02:24.824Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.824Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-11-17T15:02:48.786Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-11-08T13:46:04.940Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: For new Parse Server options, verify that the option is documented in src/Options/index.js and that npm run definitions has been executed to reflect changes in src/Options/docs.js and src/Options/Definitions.js. README.md documentation is a bonus but not required for new options.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-08-26T14:06:31.853Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: spec/CloudCode.spec.js:446-469
Timestamp: 2025-08-26T14:06:31.853Z
Learning: In the Parse Server codebase, when handling query objects in maybeRunAfterFindTrigger, objects without a where property that contain options like limit/skip should be treated as query JSON with an empty where clause using the spread pattern { where: {}, ...query }, not nested as { where: query }.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-10-16T19:27:05.311Z
Learnt from: Moumouls
Repo: parse-community/parse-server PR: 9883
File: spec/CloudCodeLogger.spec.js:410-412
Timestamp: 2025-10-16T19:27:05.311Z
Learning: In spec/CloudCodeLogger.spec.js, the test "should log cloud function triggers using the silent log level" (around lines 383-420) is known to be flaky and requires the extra `await new Promise(resolve => setTimeout(resolve, 100))` timeout after awaiting `afterSavePromise` for reliability, even though it may appear redundant.
Applied to files:
src/RestWrite.js
📚 Learning: 2025-08-27T12:33:06.237Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: src/triggers.js:467-477
Timestamp: 2025-08-27T12:33:06.237Z
Learning: In the Parse Server codebase, maybeRunAfterFindTrigger is called in production with Parse.Query objects constructed via withJSON(), so the plain object query handling bug only affects tests, not production code paths.
Applied to files:
src/RestQuery.js
🧬 Code graph analysis (1)
src/RestQuery.js (2)
src/rest.js (2)
require(15-15)require(16-16)src/SharedRest.js (1)
require(9-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: PostgreSQL 16, PostGIS 3.5
- GitHub Check: PostgreSQL 18, PostGIS 3.6
- GitHub Check: PostgreSQL 15, PostGIS 3.5
- GitHub Check: PostgreSQL 17, PostGIS 3.5
- GitHub Check: Redis Cache
- GitHub Check: Node 18
- GitHub Check: Node 22
- GitHub Check: MongoDB 8, ReplicaSet
- GitHub Check: PostgreSQL 15, PostGIS 3.3
- GitHub Check: PostgreSQL 15, PostGIS 3.4
- GitHub Check: Node 20
- GitHub Check: MongoDB 6, ReplicaSet
- GitHub Check: MongoDB 7, ReplicaSet
- GitHub Check: Docker Build
- GitHub Check: Benchmarks
🔇 Additional comments (10)
src/RestQuery.js (5)
10-10: LGTM: Import aligns with sanitized error pattern.The import of
createSanitizedErroris consistent with the pattern used in other files (src/rest.js, src/SharedRest.js) and supports the security error sanitization objective.
124-124: LGTM: Session validation error properly sanitized.Replacing the direct Parse.Error with
createSanitizedErrorensures that detailed session token information is logged server-side while returning a generic "Permission denied" message to clients, aligning with the security objectives.
425-428: LGTM: Non-existent class error properly sanitized.Using
createSanitizedErrorhere prevents exposing the non-existent class name to clients while preserving it in server logs. This aligns with the PR objective to sanitize authorization-related error messages.
804-807: LGTM: Protected field error properly sanitized.Converting this error to use
createSanitizedErrorprevents clients from discovering protected field names and class details through error messages. The detailed information remains available in server logs for debugging.
55-55: Update enforceRoleSecurity function signature to accept config parameter.The function definition in src/SharedRest.js:12 accepts only 3 parameters
(method, className, auth), but the call in src/RestQuery.js:55 passes 4 parameters includingconfig. The function signature must be updated to:function enforceRoleSecurity(method, className, auth, config) {All other call sites in src/rest.js continue to pass 3 parameters and will work with this change.
⛔ Skipped due to learnings
Learnt from: EmpiDev Repo: parse-community/parse-server PR: 9770 File: src/triggers.js:446-454 Timestamp: 2025-08-27T09:08:34.252Z Learning: When analyzing function signature changes in Parse Server codebase, verify that call sites are actually incorrect before flagging them. Passing tests are a strong indicator that function calls are already properly aligned with new signatures.src/RestWrite.js (5)
20-20: LGTM! Import statement is correct.The import of
createSanitizedErroris properly placed and follows the module import conventions.
31-37: LGTM! Read-only master key check correctly sanitized.The error sanitization appropriately logs the detailed reason server-side while returning a generic permission error to the client, preventing exposure of internal authorization details about the read-only master key.
191-212: LGTM! Client class creation validation correctly sanitized.The error sanitization appropriately logs the specific class name server-side for debugging while returning a generic permission error to the client, preventing information disclosure about internal class structure and authorization rules.
657-668: LGTM! Email verification field restriction correctly sanitized.The error sanitization prevents clients from discovering the internal restriction on manual
emailVerifiedupdates while logging the detailed reason server-side.
1442-1459: LGTM! Unauthenticated user modification check correctly sanitized.The error sanitization appropriately logs the specific user objectId server-side while returning a generic session error to the client, preventing enumeration of valid user IDs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/Routers/ClassesRouter.js (1)
7-7: Remove unused import.The
defaultLoggerimport is not used anywhere in this file. IfcreateSanitizedErrorhandles logging internally (as suggested by the PR objectives), this import can be removed.Apply this diff to remove the unused import:
-import defaultLogger from '../logger';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/Routers/ClassesRouter.js(2 hunks)src/Routers/FilesRouter.js(2 hunks)src/middlewares.js(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/Routers/FilesRouter.js
- src/middlewares.js
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.
📚 Learning: 2025-04-30T19:31:35.344Z
Learnt from: RahulLanjewar93
Repo: parse-community/parse-server PR: 9744
File: spec/ParseLiveQuery.spec.js:0-0
Timestamp: 2025-04-30T19:31:35.344Z
Learning: In the Parse Server codebase, the functions in QueryTools.js are typically tested through end-to-end behavior tests rather than direct unit tests, even though the functions are exported from the module.
Applied to files:
src/Routers/ClassesRouter.js
🔇 Additional comments (2)
src/Routers/ClassesRouter.js (2)
58-58: The selective sanitization application appears intentional, but verify OBJECT_NOT_FOUND inconsistency across the codebase.Analysis shows
createSanitizedErroris intentionally applied to security-sensitive errors (authorization, authentication) while validation/query errors remain unsanitized for client feedback. However,OBJECT_NOT_FOUNDis inconsistently handled: it's sanitized in SchemaController.js (lines 1408, 1413) but not in ClassesRouter.js line 93. The INVALID_QUERY errors at lines 58 and 183 don't appear to be sanitized anywhere in the codebase, suggesting this is intentional for validation feedback. Consider either: (1) verifying the OBJECT_NOT_FOUND inconsistency is intentional, or (2) applying consistent sanitization if line 93 should be treated as security-sensitive.
116-116: The change is correct and properly implements error sanitization for authorization failures.The
createSanitizedErrorfunction correctly logs the detailed message ('Invalid object ID.') server-side viadefaultLogger.error()while returning a generic'Permission denied'message to the client. This aligns with the PR objective to prevent sensitive information leakage.The selective sanitization at line 116 (OPERATION_FORBIDDEN) while leaving other errors unsanitized (lines 58, 93, 183 - which are INVALID_QUERY and OBJECT_NOT_FOUND in non-permission contexts) is intentional and consistent with the codebase pattern: authorization errors are sanitized to avoid leaking implementation details, while validation errors remain specific to help clients understand their mistakes.
mtrezza
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just the failing lint
# [8.5.0-alpha.13](8.5.0-alpha.12...8.5.0-alpha.13) (2025-11-23) ### Bug Fixes * Server internal error details leaking in error messages returned to clients ([#9937](#9937)) ([50edb5a](50edb5a))
|
🎉 This change has been released in version 8.5.0-alpha.13 |
Pull Request
Issue
Fixes: #8958
Summary by CodeRabbit
New Features
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.